/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package systole.processor.correlation;

import java.math.BigDecimal;
import systole.domain.signals.Segment;
import systole.math.MathUtils;

/**
 *
 * @author jmj
 */
public abstract class Correlation {

    protected Segment pattern;

    /**
     *
     * @param pattern
     * @throws IllegalArgumentException If pattern is null
     */
    public Correlation(Segment pattern) {
        if ((pattern == null)) {
            throw new IllegalArgumentException("Params not valid");
        }
        this.pattern = pattern;
    }

    /**
     * @param segment
     * @param initPosOfCorrelation
     * @param endPosOfCorrelation 
     * @return correlation of segment
     */
    protected BigDecimal correlate(Segment segment, int initPosOfCorrelation, int endPosOfCorrelation) {

        endPosOfCorrelation = ((endPosOfCorrelation > this.pattern.size()) ? this.pattern.size() - 1 : endPosOfCorrelation);

        int lenght = (endPosOfCorrelation - initPosOfCorrelation);
        BigDecimal patternAVG = this.pattern.subSegment(initPosOfCorrelation, endPosOfCorrelation).avg();
        BigDecimal segmentAVG = segment.subSegment(initPosOfCorrelation, endPosOfCorrelation).avg();

        BigDecimal cov = BigDecimal.ZERO;
        BigDecimal varX = BigDecimal.ZERO;
        BigDecimal varY = BigDecimal.ZERO;
        int i = initPosOfCorrelation;
        while (i < endPosOfCorrelation) {
            BigDecimal segmentValue = ((segment.size() <= i) ? BigDecimal.ZERO : segment.elementAt(i));
            cov = cov.add((this.pattern.elementAt(i).subtract(patternAVG)).multiply(segmentValue.subtract(segmentAVG)));
            varX = varX.add(this.pattern.elementAt(i).subtract(patternAVG).pow(2));
            varY = varY.add(segmentValue.subtract(segmentAVG).pow(2));
            i++;
        }
        cov = cov.divide(new BigDecimal(lenght),MathUtils.CONTEXT);
        varX =  BigDecimal.valueOf(StrictMath.sqrt((varX.divide(new BigDecimal(lenght),MathUtils.CONTEXT)).doubleValue()));
        varY = BigDecimal.valueOf(StrictMath.sqrt(varY.divide(new BigDecimal(lenght),MathUtils.CONTEXT).doubleValue()));
        return (cov.divide(varX.multiply(varY),MathUtils.CONTEXT));
    }

    /**
     *
     * @param segment
     * @return segment correlation from pattern
     */
    public abstract BigDecimal correlate(Segment segment);
}
